package com.lwj.service.common.file;

import com.lwj.config.ConfigProperties;
import com.lwj.constant.FileMimeEnum;
import com.lwj.constant.FilePermissionEnum;
import com.lwj.dto.file.FilePermissionDto;
import com.lwj.exception.BusinessException;
import com.lwj.model.configuration.FileManage;
import com.lwj.service.DozerService;
import com.lwj.service.SpringUtil;
import com.lwj.service.configuration.FileManageService;
import com.lwj.utils.ImageUtils;
import com.lwj.utils.UuidUtil;
import com.lwj.vo.common.FileInfoVo;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.net.URLEncoder;
import java.util.LinkedList;

@Service
public class FileServiceImpl  implements FileService {
    protected static final Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);
    @Autowired
    private ConfigProperties configProperties;
    @Autowired
    private FileManageService fileManageService;
    @Autowired
    private DozerService dozerService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileInfoVo upload(MultipartFile file, String relationId, String code) {
        FilePermission filePermission = filePermission(relationId, code);
        FilePermissionDto filePermissionDto = new FilePermissionDto();
        filePermissionDto.setCode(code);
        filePermissionDto.setRelationId(relationId);
        //校验权限
        filePermission.checkUpload(filePermissionDto);
        //校验数据
        try {
            String fileId= UuidUtil.getUuid();
            String path=filePath(fileId,relationId,"",file.getOriginalFilename());
            File f=new File(path);
            FileUtils.writeByteArrayToFile(f,file.getBytes());
            FileInfoVo fileInfoVo = saveFileManage(fileId,file, relationId, path, "", code);
            return fileInfoVo;
        }catch (Exception e){
            logger.error("上传报错",e);
            throw new BusinessException("上传报错");
        }
    }

    @Override
    public void del(String fileId,String code) {
        FileManage fileManage = fileManageService.selectByPrimaryKey(fileId, true);
        String path = fileManage.getPath();
        String suffix=path.substring(path.lastIndexOf("."));
        String path500 = path.replace(suffix, "_500"+suffix);
        String path250 = path.replace(suffix, "_250"+suffix);
        String path2000 = path.replace(suffix, "_2000"+suffix);
        deleteFile(path,path500,path250,path2000);
        fileManageService.deleteByPrimaryKey(fileId);

    }

    @Override
    public byte[] down(String fileId, Integer size,String code) {
        try {
            FileManage fileManage = fileManageService.selectByPrimaryKey(fileId,true);
            String path = fileManage.getPath();
            File file=new File(path);
            Boolean isImage = FileMimeEnum.isImage(fileManage.getFileName());
            Boolean check=size!=null && isImage &&(size == 250 || size == 2000 || size == 500);
            //需要压缩
            if(check){
                String suffix=path.substring(path.lastIndexOf("."));
                String replace = path.replace(suffix, "_" + size + suffix);
                File zipFile = new File(replace);
                if(!zipFile.exists()){
                    byte[]  bytes = ImageUtils.imageChangeSize(file, size);
                    FileUtils.writeByteArrayToFile(zipFile, bytes);
                    return bytes;
                }else {
                    return FileUtils.readFileToByteArray(zipFile);
                }
            }
            return  FileUtils.readFileToByteArray(file);
        }catch (Exception e){
            logger.error("下载报错",e);
            throw new BusinessException("下载报错");
        }
    }

    @Override
    public void down2(String fileId, Integer size,String code) {
        FileInputStream fis=null;
        try {
            FileManage fileManage = fileManageService.selectByPrimaryKey(fileId,true);
            HttpServletResponse resp = SpringUtil.getResponse();
            resp.setHeader("content-type","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            //  设置请求头打开方式：content-disposition ，对应 attachment附件形式打开
            resp.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(fileManage.getFileName()));
            //  用字节流关联
            fis = new FileInputStream(fileManage.getPath());
            //  将输入流的数据写出到输出流中
            ServletOutputStream outputStream = resp.getOutputStream();
            //缓冲区
            byte[] buff = new byte[1024 * 8];
            int len ;
            while((len = fis.read(buff)) != -1){
                outputStream.write(buff,0,len);
            }
        }catch (Exception e){
            logger.error("下载报错",e);
            throw new BusinessException("下载报错");
        }finally {
           ImageUtils.close(fis);
        }
    }

    @Override
    public void rotateImage(Integer angle, String fileId, String code) {
        try{
            FileManage fileManage = fileManageService.selectByPrimaryKey(fileId, true);
            String path = fileManage.getPath();
            File file = new File(path);
            BufferedImage bufferedImage = ImageUtils.getRotateImage(angle, file);
            ImageIO.write(bufferedImage, path.substring(path.lastIndexOf(".") + 1), file);
            String suffix=path.substring(path.lastIndexOf("."));
            String path500 = path.replace(suffix, "_500"+suffix);
            String path250 = path.replace(suffix, "_250"+suffix);
            String path2000 = path.replace(suffix, "_2000"+suffix);
            deleteFile(path250,path500,path2000);
        }catch (Exception e){
            logger.error("旋转图片报错",e);
            throw new BusinessException("旋转图片报错");
        }
    }
    public void deleteFile(String ... fileName){
        for (int i = 0; i < fileName.length; i++) {
            String s = fileName[i];
            File file = new File(s);
            if(file.exists()){
                file.delete();
            }
        }
    }

    public FileInfoVo saveFileManage(String fileId,MultipartFile file, String relationId,  String path, String source, String code){
        int index=fileManageService.maxIndex(relationId)+1;
        FileManage fileManage = new FileManage(fileId,file.getOriginalFilename(), (int) file.getSize(), file.getContentType(), relationId, index, path, source, code);
        fileManageService.insertSelective(fileManage);
        return dozerService.map(fileManage,FileInfoVo.class);
    }
    private String filePath(String fileId, String relationId, String createTime, String filename) {
        createTime=createTime.split(" ")[0];
        String[] split = createTime.split("-");
        String year=split[0];
        String month=split[1];
        String day=split[2];
        String dir = configProperties.getFilePath()+year+"/"+month+"/"+day+"/"+relationId;
        File dirFile=new File(dir);
        if(!dirFile.exists()){
            dirFile.mkdir();
        }
        String newFileName=fileId+"."+filename.split("\\.")[1];
        return dir+"/"+newFileName;
    }

    /**
     * 采用链表来存储遍历到的文件夹
     * @param path
     */
    public static void traverseFile(String path){
        File[] fileArray;
        File file=new File(path);
        if(file.exists()){
            LinkedList<File> list = new LinkedList<File>();
            list.add(file);
            while(!list.isEmpty()){
                File fileFirst = list.removeFirst();
                fileArray = fileFirst.listFiles();
                for(File f:fileArray){
                    if(f.isDirectory()){
                        System.out.println("文件夹："+f.getAbsolutePath());
                        list.add(f);
                    }else{
                        System.out.println("文件："+f.getAbsolutePath());
                    }
                }
            }
        }else{
            System.out.println("文件不存在！");
        }
    }

    /**
     * 递归方式 遍历文件
     * @param path
     */
    public static void traverseFile1(String path){
        File file = new File(path);
        if(file.exists()){
            File[] fileArray = file.listFiles();
            for(File f : fileArray){
                String absolutePath = f.getAbsolutePath();
                if(f.isDirectory()){
                    System.out.println("文件夹："+absolutePath);
                    traverseFile1(absolutePath);
                }else{
                    System.out.println("文件："+absolutePath);
                }
            }
        }else{
            System.out.println("文件不存在！");
        }
    }


    private FilePermission filePermission(String relationId, String code){
        if (StringUtils.isEmpty(relationId)){
            return SpringUtil.getBean(TemFilePermission.class);
        }
        Class<FilePermission> filePermissionClass = FilePermissionEnum.ofClass(code);
        return SpringUtil.getBean(filePermissionClass);
    }

}
